/**
* \file DGVTable.cpp
*
* \brief This file defines the class for display data using tables using only Qt.
* \author Shekhar S. Chandra, 2008
*
* This file is part of DGV Library.
*
* DGV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DGV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DGV.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "DGVTable.h"

#include <fstream>
//#include <QtCore/QtDebug>

DGVTable::DGVTable(QWidget *parent) : QTableWidget(parent)
{
    createConnections();
}

DGVTable::~DGVTable()
{

}

void DGVTable::setName(QString filename)
{
    name = filename;
    setWindowTitle(strippedNamePrefix());
}

void DGVTable::setItem(int row, int column, tableType value)
{
    QTableWidgetItem *item = NULL;
    QString tmp;

    tmp = tmp.setNum(value);
    item = new QTableWidgetItem();
    item->setText(tmp);
    QTableWidget::setItem(row,column,item);
    //tableItems.append(item);
}

void DGVTable::setItem(int row, int column, QString value)
{
    QTableWidgetItem *item = NULL;

    item = new QTableWidgetItem();
    item->setText(value);
    QTableWidget::setItem(row,column,item);
    //tableItems.append(item);
}

tableType DGVTable::getItem(int x, int y)
{
    QString tmp;

    tmp = QTableWidget::item(x,y)->text();

    return tmp.toDouble();
}

void DGVTable::zapSelection()
{
    QList<QTableWidgetItem*> selection;

    selection = QTableWidget::selectedItems();
    for(int j = 0; j < selection.size(); j ++)
        selection[j]->setText("0");
}

void DGVTable::delSelection()
{
    QList<QTableWidgetSelectionRange> selectedRange;
    int size = 0, start = 0;

    selectedRange = QTableWidget::selectedRanges();

    for(int j = 0; j < selectedRange.size(); j ++)
    {
        if(selectedRange[j].columnCount() < selectedRange[j].rowCount())
        {
            ///Columns selected
            size = selectedRange[j].columnCount();
            start = selectedRange[j].leftColumn();
            /*QMessageBox::warning(this, "DGV",
                    "Do you wish to delete columns and all data within it?\n"
                    "Check the data Delimiters and Try opening the file again.");*/
            for(int j = start; j < size+start; j ++)
                QTableWidget::removeColumn(j);
        }
        else
        {
            size = selectedRange[j].rowCount();
            start = selectedRange[j].topRow();

            for(int j = start; j < size+start; j ++)
                QTableWidget::removeRow(j);
        }
    }
}

void DGVTable::plotSelection()
{
    Array<Array<double,1>,1> selectedData; //!< Array of Array is done to have variable-sized rows
    Array<Array<double,1>,1> selectedDataX;
    QList<QTableWidgetItem*> selection;
    QList<QTableWidgetSelectionRange> selectedRange;
    DGVPlot *tmpPlot = NULL;
    int size = 0, start = 0, count = 0;

    ///Get selected items, which is put into 1D form
    selection = QTableWidget::selectedItems();
    ///Get the actual ranges selected
    selectedRange = QTableWidget::selectedRanges();
    ///Resize the Blitz arrays
    selectedData.resizeAndPreserve(selectedRange.size());
    selectedDataX.resizeAndPreserve(selectedRange.size());
    ///\todo Bug: Shift selection only works for one selection. Control selection works correctly
    ///\todo Column plot doesn't work.

    cerr << "Bug Warning: If selections not appearing in plot, use Crtl key instead of Shift key.\n";
    ///Copy the data ordered row wise
    for(int j = 0; j < selectedRange.size(); j ++)
    {
        ///Determine shape of selection
        if(selectedRange[j].columnCount() < selectedRange[j].rowCount())
        {
            size = selectedRange[j].rowCount();
            start = selectedRange[j].topRow();
        }
        else
        {
            size = selectedRange[j].columnCount();
            start = selectedRange[j].leftColumn();
        }

        selectedData(j).resizeAndPreserve(size);
        selectedDataX(j).resizeAndPreserve(size);
        for(int k = count; k < count+size; k ++)
        {
            selectedData(j)(k-count) = selection[k]->text().toDouble();
            selectedDataX(j)(k-count) = start+(k-count);
        }
        count += size;
    }

    tmpPlot = new DGVPlot(this);
    tmpPlot->createCurvePlots(selectedDataX,selectedData,"Selection Plot");

    emit plotAvailable(tmpPlot);
}

void DGVTable::scanSelection()
{
    //DGVAnimate *ani = new DGVAnimate(this);
    /*QList<QTableWidgetSelectionRange> selectedRange;
    int size = 0, start = 0;

    selectedRange = QTableWidget::selectedRanges();

    for(int j = 0; j < selectedRange.size(); j ++)
    {
        if(selectedRange[j].columnCount() < selectedRange[j].rowCount())
        {
            ///Columns selected
            size = selectedRange[j].rowCount();
            start = selectedRange[j].topRow();

        }
        else
        {
            size = selectedRange[j].columnCount();
            start = selectedRange[j].leftColumn();

        }
    }*/

    //emit animAvailable(ani);
}

void DGVTable::saveSelection()
{
    QFileDialog *fileSaver = new QFileDialog(this);
    QList<QTableWidgetItem*> selection;
    QList<QTableWidgetSelectionRange> selectedRange;
    int size = 0, start = 0, count = 0;

    QString filename = fileSaver->getSaveFileName(this,
                           tr("Select File Name to Save"),
                           ".",
                           tr("Data Files (*.csv)"));

    if (!filename.isEmpty())
    {
        ///Get selected items, which is put into 1D form
        selection = QTableWidget::selectedItems();
        ///Get the actual ranges selected
        selectedRange = QTableWidget::selectedRanges();

        ///\todo Bug: Shift selection only works for one selection. Control selection works correctly
        ///\todo Column saves may work.

        cerr << "Bug Warning: If selections not appearing in plot, use Crtl key instead of Shift key.\n";

        QFile file("test.csv");
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
             return;
        QTextStream *out = new QTextStream(&file);

        for(int j = 0; j < selectedRange.size(); j ++)
        {
            ///Determine shape of selection
            if(selectedRange[j].columnCount() < selectedRange[j].rowCount())
            {
                size = selectedRange[j].rowCount();
                start = selectedRange[j].topRow();
            }
            else
            {
                size = selectedRange[j].columnCount();
                start = selectedRange[j].leftColumn();
            }

            for(int k = count; k < count+size; k ++)
                (*out) << selection[k]->text().toDouble() << ", ";
            (*out) << endl;

            count += size;
        }

        delete out;
        file.close();
    }
}

void DGVTable::saveAll()
{
    QFileDialog *fileSaver = new QFileDialog(this);
    QString filename = fileSaver->getSaveFileName(this,
                           tr("Select File Name to Save"),
                           ".",
                           tr("Data Files (*.csv)"));

    if (!filename.isEmpty())
    {
        QFile file(filename);

        if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
             return;

        QTextStream *out = new QTextStream(&file);

        for(int j = 0; j < QTableWidget::rowCount(); j ++)
        {
            for(int k = 0; k < QTableWidget::columnCount(); k ++)
                (*out) << item(j,k)->text().toDouble() << ", ";
            (*out) << endl;
        }

        delete out;
        file.close();
    }
}

bool DGVTable::loadCSV(const QString filename)
{
    int cols = 0;
    QFile file(filename);
    QString line;
    tableType tmp = 0;
    char comma;

    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
         return false;

    ///Detect CSV structure
    ///\todo Test Delimiter Detection for various cases
    QTextStream *in = new QTextStream(&file);
    line = in->readLine(); //!< Use first line for detection
    line.simplified();

    if(line.contains(","))
        cols = line.count(",");
    else if(line.contains(" "))
        cols = line.count(" ") + 1;
    else
        return false;

    delete in;
    file.reset(); //!< Restart stream
    in = new QTextStream(&file);

    //cerr << "POS: " << file.pos() << endl;
    if(cols > 0)
    {
        setColumnCount(cols);
        while(!in->atEnd())
        {
            insertRow(QTableWidget::rowCount());
            for(int k = 0; k < cols; k ++)
            {
                (*in) >> tmp;
                (*in) >> comma;
                //cerr << "j: " << QTableWidget::rowCount()-1 << " k: " << k << " Value: " << tmp << endl;
                setItem(QTableWidget::rowCount()-1,k,tmp);
            }
        }
    }

    delete in;
    return true;
}

void DGVTable::setData(Array<tableType,2> &values)
{
    setRowCount(values.rows());
    setColumnCount(values.cols());
    for(int j = 0; j < values.rows(); j ++)
        for(int k = 0; k < values.cols(); k ++)
            setItem(j,k,values(j,k));
}

Array<tableType,2>& DGVTable::data()
{
    tableData.resize(QTableWidget::rowCount(),QTableWidget::columnCount());

    for(int j = 0; j < QTableWidget::rowCount(); j ++)
        for(int k = 0; k < QTableWidget::columnCount(); k ++)
            tableData(j,k) = getItem(j,k);

    return tableData;
}

QString DGVTable::strippedName()
{
    return QFileInfo(name).fileName();
}

QString DGVTable::strippedNamePrefix()
{
    return "Table: " + QFileInfo(name).fileName();
}

void DGVTable::contextMenuEvent(QContextMenuEvent *event)
{
    QMenu menu(this);

    zapAct = menu.addAction(tr("&Zap"));
    zapAct->setShortcut(tr("Ctrl+Shift+z"));

    delAct = menu.addAction(tr("&Delete"));
    delAct->setShortcut(tr("Ctrl+Shift+d"));

    menu.addSeparator();
    plotAct = menu.addAction(tr("&Plot"));
    plotAct->setShortcut(tr("Ctrl+Shift+p"));

    scanAct = menu.addAction(tr("&Scan"));
    scanAct->setShortcut(tr("Ctrl+Shift+a"));

    menu.addSeparator();
    saveAct = menu.addAction(tr("&Save Selection"));
    saveAct->setShortcut(tr("Ctrl+Shift+s"));
    saveAllAct = menu.addAction(tr("Save &Entire Table"));
    saveAllAct->setShortcut(tr("Ctrl+Shift+e"));
    closeAct = menu.addAction(tr("&Close"));
    closeAct->setShortcut(tr("Ctrl+Shift+c"));

    connect(zapAct, SIGNAL(triggered()), this, SLOT(zapSelection()));
    connect(delAct, SIGNAL(triggered()), this, SLOT(delSelection()));
    connect(plotAct, SIGNAL(triggered()), this, SLOT(plotSelection()));
    connect(scanAct, SIGNAL(triggered()), this, SLOT(scanSelection()));
    connect(saveAct, SIGNAL(triggered()), this, SLOT(saveSelection()));
    connect(saveAllAct, SIGNAL(triggered()), this, SLOT(saveAll()));
    connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));

    menu.exec(event->globalPos());
}

void DGVTable::createConnections()
{

}
